#include "audio_render.h"
#include "aki/jsbind.h"

void AudioFrameSlice::Deleter(void *frameSlice)
{
    if (frameSlice != nullptr) {
        delete [] reinterpret_cast<uint8_t *>(frameSlice);
        frameSlice = nullptr;
    }
}

int32_t AudioRender::RenderCallbacks::OnWriteData(OH_AudioRenderer *renderer, void *userData, void *buffer, int32_t length)
{
    uint8_t *data = reinterpret_cast<uint8_t*>(buffer);
    memset(data, 0, length);
    AudioRender *audioRender = reinterpret_cast<AudioRender*>(userData);
    if (audioRender == nullptr) {
        return 0;
    }
    size_t res = 0, curLength = 0;
    while (!audioRender->IsEmptyFrameSlice() && curLength < length) {
        AudioFrameSlice &audioFrame = audioRender->FrontFrameSlice();
        size_t leftBuff = audioFrame.bufferLen - audioFrame.bufferUsed;
        if ((length - curLength) >= leftBuff) {
            memcpy(data + curLength, audioFrame.buffer.get() + audioFrame.bufferUsed, leftBuff);
            curLength += leftBuff;
            audioRender->PopFrameSlice();
        } else {
            res = length - curLength;
            memcpy(data + curLength, audioFrame.buffer.get() + audioFrame.bufferUsed, res);
            audioFrame.bufferUsed += res;
            curLength += res;
        }
    }
    return 0;
}

AudioRender::AudioRender(int32_t sampleRate, int32_t channels, OH_AudioStream_SampleFormat sampleFormat, int32_t bitWidth)
:sampleRate_(sampleRate), channels_(channels), sampleFormat_("S16N", sampleFormat, bitWidth)
{
}

AudioRender::~AudioRender()
{
    Stop();
    if (audioRenderer_ != nullptr) {
        OH_AudioRenderer_Release(audioRenderer_);
        audioRenderer_ = nullptr;
    }
    
    if (audioStreamBuilder_ != nullptr) {
        OH_AudioStreamBuilder_Destroy(audioStreamBuilder_);
        audioStreamBuilder_ = nullptr;
    }
    
    CleanFrameSliceQueue();
}

int32_t AudioRender::Init()
{
    if (state_ != PlayerState::NONE) {
        return -1;
    }
    OH_AudioStream_Result result = AUDIOSTREAM_SUCCESS;
    result = OH_AudioStreamBuilder_Create(&audioStreamBuilder_, AUDIOSTREAM_TYPE_RENDERER);
    if (result != AUDIOSTREAM_SUCCESS) {
        AKI_LOG(ERROR) << "OH_AudioStreamBuilder_Create failed! status:" << result;
        return result;
    }
    
    result = OH_AudioStreamBuilder_SetSamplingRate(audioStreamBuilder_, sampleRate_);
    if (result != AUDIOSTREAM_SUCCESS) {
        AKI_LOG(ERROR) << "OH_AudioStreamBuilder_SetSamplingRate failed! status:" << result;
        return result;
    }

    result = OH_AudioStreamBuilder_SetChannelCount(audioStreamBuilder_, channels_);
    if (result != AUDIOSTREAM_SUCCESS) {
        AKI_LOG(ERROR) << "OH_AudioStreamBuilder_SetChannelCount failed! status:" << result;
        return result;
    }

    result = OH_AudioStreamBuilder_SetSampleFormat(audioStreamBuilder_, std::get<1>(sampleFormat_));
    if (result != AUDIOSTREAM_SUCCESS) {
        AKI_LOG(ERROR) << "OH_AudioStreamBuilder_SetSampleFormat failed! status:" << result;
        return result;
    }

    result = OH_AudioStreamBuilder_SetEncodingType(audioStreamBuilder_, AUDIOSTREAM_ENCODING_TYPE_RAW);
    if (result != AUDIOSTREAM_SUCCESS) {
        AKI_LOG(ERROR) << "OH_AudioStreamBuilder_SetEncodingType failed! status:" << result;
        return result;
    }
#if LATENCY_MODE_FAST
    result = OH_AudioStreamBuilder_SetLatencyMode(audioStreamBuilder_, AUDIOSTREAM_LATENCY_MODE_FAST);
    if (result != AUDIOSTREAM_SUCCESS) {
        AKI_LOG(ERROR) << "OH_AudioStreamBuilder_SetLatencyMode failed! status:" << result;
        return result;
    }

    // 低延时可以设置5, 10, 15, 20
    result = OH_AudioStreamBuilder_SetFrameSizeInCallback(audioStreamBuilder_, 5);
    if (result != AUDIOSTREAM_SUCCESS) {
        AKI_LOG(ERROR) << "OH_AudioStreamBuilder_SetLatencyMode failed! status:" << result;
        return result;
    }
#endif
    result = OH_AudioStreamBuilder_SetRendererInfo(audioStreamBuilder_, AUDIOSTREAM_USAGE_MOVIE);
    if (result != AUDIOSTREAM_SUCCESS) {
        AKI_LOG(ERROR) << "OH_AudioStreamBuilder_SetLatencyMode failed! status:" << result;
        return result;
    }
    
    OH_AudioRenderer_Callbacks callbacks;
    callbacks.OH_AudioRenderer_OnWriteData = RenderCallbacks::OnWriteData;
    callbacks.OH_AudioRenderer_OnError = nullptr;
    callbacks.OH_AudioRenderer_OnInterruptEvent = nullptr;
    callbacks.OH_AudioRenderer_OnStreamEvent = nullptr;

    result = OH_AudioStreamBuilder_SetRendererCallback(audioStreamBuilder_, callbacks, this);
    if (result != AUDIOSTREAM_SUCCESS) {
        AKI_LOG(ERROR) << "OH_AudioStreamBuilder_SetLatencyMode failed! status:" << result;
        return result;
    }

    result = OH_AudioStreamBuilder_GenerateRenderer(audioStreamBuilder_, &audioRenderer_);
    if (result != AUDIOSTREAM_SUCCESS) {
        AKI_LOG(ERROR) << "OH_AudioStreamBuilder_SetLatencyMode failed! status:" << result;
        return result;
    }
    state_ = PlayerState::INIT;
    return 0;
}

int32_t AudioRender::Play()
{
    if (state_ == PlayerState::RUNNING) {
        return AUDIOSTREAM_SUCCESS;
    }

    OH_AudioStream_Result result = OH_AudioRenderer_Start(audioRenderer_);
    if (result != AUDIOSTREAM_SUCCESS) {
        return result;
    }
    state_ = PlayerState::RUNNING;
    return AUDIOSTREAM_SUCCESS;
}

int32_t AudioRender::Pause()
{
    if (state_ == PlayerState::PAUSE) {
        return AUDIOSTREAM_SUCCESS;
    }

    OH_AudioStream_Result result = OH_AudioRenderer_Pause(audioRenderer_);
    if (result != AUDIOSTREAM_SUCCESS) {
        return result;
    }
    state_ = PlayerState::PAUSE;
    return AUDIOSTREAM_SUCCESS;
}

int32_t AudioRender::Resume()
{
    if (state_ == PlayerState::RUNNING) {
        return AUDIOSTREAM_SUCCESS;
    }
    OH_AudioStream_Result result = OH_AudioRenderer_Start(audioRenderer_);
    if (result != AUDIOSTREAM_SUCCESS) {
        return result;
    }
    state_ = PlayerState::RUNNING;
    return AUDIOSTREAM_SUCCESS;
}

int32_t AudioRender::Flush()
{
    OH_AudioStream_Result result = OH_AudioRenderer_Flush(audioRenderer_);
    if (result != AUDIOSTREAM_SUCCESS) {
        return result;
    }
    return AUDIOSTREAM_SUCCESS;
}

int32_t AudioRender::Stop()
{
    OH_AudioStream_Result result = OH_AudioRenderer_Stop(audioRenderer_);
    if (result != AUDIOSTREAM_SUCCESS) {
        return result;
    }
    CleanFrameSliceQueue();
    state_ = PlayerState::STOP;
    return AUDIOSTREAM_SUCCESS;
}

int32_t AudioRender::PushFrameSlice(const AudioFrameSlice &frameSlice)
{
    if (state_ == PlayerState::STOP) {
        return -1;
    }
    std::lock_guard<std::mutex> lock(queueMutex_);
    frameQueue_.push(frameSlice);
    return 0;
}

int32_t AudioRender::PopFrameSlice()
{
    std::lock_guard<std::mutex> lock(queueMutex_);
    frameQueue_.pop();
    return 0;
}

bool AudioRender::IsEmptyFrameSlice()
{
    std::lock_guard<std::mutex> lock(queueMutex_);
    return frameQueue_.empty();
}

AudioFrameSlice &AudioRender::FrontFrameSlice()
{
    std::lock_guard<std::mutex> lock(queueMutex_);
    return frameQueue_.front();
}

bool AudioRender::CleanFrameSliceQueue()
{
    while (!IsEmptyFrameSlice()) {
        PopFrameSlice();
    }
    return true;
}

std::tuple<std::string, OH_AudioStream_SampleFormat, int32_t> &AudioRender::SampleFormat()
{
    return sampleFormat_;
}

int32_t AudioRender::SampleRate() const
{
    return sampleRate_;    
}

int32_t AudioRender::Channels() const
{
    return channels_;
}